{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modClassRessources;

interface

uses Classes, SysUtils, modCore, modBaseType, sFonctionsChaines;


type
     TListRessources = class(TList)
     private
         FDebugProc: TsfcProcStatus;

         function LoadLigneItem(Ligne: string): TOGResUsed;
         procedure DoDebug(const Msg: string);
     public
         // modifie le champ ActiviteForOptimization à -1 pour tous les éléments
         procedure ResetOptimization;



         function GetProdParHeure: TOGRessourceAll;



         function GetDonneesAPoster: string;



         // Manipulation de pointeur
         function Ajout(Element: TOGResUsed): POGResUsed;
         procedure ClearAndFree;

         // Duplique la liste (les objets pointés)
         procedure DupliqueTo(Destination: TList);


         // IO
         procedure SaveToFile(var F: TextFile);
         function LoadFromFile(var F: TextFile; NbElements: integer): integer;

         // Debug
         property DebugProc : TsfcProcStatus read FDebugProc write FDebugProc;
         procedure SendToDebugAllInfo;
     end;


     
// Calcul les ressources produite par heure, NE s'occupe PAS de calculer le
// facteur de production
function mcrGetCalculTotalParHeure(CurrProduct: TList): TOGRessourceAll;

procedure CalculQuandOnPourraConstruire(Element: TList; Prod: TList; CurrentProdParHeure, CurrRes: TOGRessourceAll);

implementation

uses modBaseRessources, modCoreRecu;

// Pour permettre la détection d'erreur de chargement
const
   CNT_ACTIVITE_ERROR = -50;


procedure CalculQuandOnPourraConstruire(Element: TList; Prod: TList; CurrentProdParHeure, CurrRes: TOGRessourceAll);
var WorkingProd: TList;
    i, j: integer;
    CurrElement: POGItemCost;
    cePrix: TOGRessourceAll;
begin

    if Element.Count = 0 then exit;

    WorkingProd := TList.Create;
    DupliqueTList(Prod, WorkingProd);

    // Production par heure en cours (sans optimisation)
    //CurrentProdParHeure := GetCalculTotalParHeure(Prod);

    GetRessourceWithoutFactorProduct(WorkingProd);

    for i := 0 to Element.Count - 1 do begin
        CurrElement := Element.Items[i];

        cePrix := mbrGetRessourceNeed(CurrRes, CurrElement.Prix);

        CurrElement.CanBeBuildIn := GetTimeNeedToProductThisRes(cePrix, CurrentProdParHeure, j);

        if CurrElement.CanBeBuildIn > 0 then begin
           GetBestActivityProduct(cePrix, WorkingProd, j);

           CurrElement.CanBeBuildInOpt := j;
        end else if CurrElement.CanBeBuildIn < 0 then begin
           // Dans ce cas là, il est impossible de construire l'élément
           // avec la production actuelle
           CurrElement.CanBeBuildInOpt := CNT_CONSTRUCTION_DISPO_NEVER_WITHTHISPROD;
           
        end else
           // Sinon l'élément est déjà constructible
           CurrElement.CanBeBuildInOpt := 0;

    end;

    FreeTList(WorkingProd);
    WorkingProd.Free;


end;


(* Voici les données que l'on a:

    Facteur de production:0.99
Production de matières premières sur la planète"PlaneteNom"
	                                   Métal    Cristal  Deutérium 	  Énergie
Revenu de base                          20         10          0        0
Mine de métal (Niveau 12)                0          0          0       0/0
Mine de cristal (Niveau 10)              0        412          0     206/207
Synthétiseur de deutérium (Niveau 9)     0          0        254     421/424
Centrale électrique solaire (Niveau 11)  0          0          0         627
Capacité de stockage 	                100k       100k       100k         -
Total:                                  20         422        254        -2

On a ceci en entrée de la fonction, et l'on a également:
Mine de métal (Niveau 12 )
Principal fournisseur de matières premières pour la construction de structures portantes et de vaisseaux.
A besoin de: Métal:7.784 Cristal:1.946
Durée de production: 58m 23s

C'est à dire ce que l'on veut construire.

La fonction renvoi le meilleur pourcentage à mettre pour construire au plus
vite ce batiment

Le tableau peut contenir plus de ligne que prévu, et les sources de revenues
ne sont pas toujours les mines et les centrales électrique (centrale
à fusion après, qui consomme du deut), il faut donc prendre chaque colonne
en compte pour chaque batiment.

Mine de métal	
Mine de cristal	
Synthétiseur de deutérium 	
Centrale électrique solaire	
Centrale électrique de fusion
Usine de robots	
Usine de nanites
Chantier spatial
Hangar de métal
Hangar de cristal
Réservoir de deutérium
Laboratoire de recherche
Silo à missile

*)


function mcrGetCalculTotalParHeure(CurrProduct: TList): TOGRessourceAll;
var CurrRes: POGResUsed;
    i: integer;
begin

     Result.Metal     := 0;
     Result.Cristal   := 0;
     Result.Deuterium := 0;
     Result.Energie   := 0;

     if CurrProduct.Count = 0 then exit;

     for i := 0 to CurrProduct.Count - 1 do begin
        CurrRes := CurrProduct.Items[i];

        Result.Metal     := Result.Metal + CurrRes.prMetal;
        Result.Cristal   := Result.Cristal + CurrRes.prCristal;
        Result.Deuterium := Result.Deuterium + CurrRes.prDeuterium;

        if CurrRes.prEnergie > 0 then begin
           // Centrale électrique
           Result.Energie := Result.Energie + CurrRes.prEnergie;

        end else begin
           // Batiment normal
           Result.Energie := Result.Energie - CurrRes.csEnergieUsed;
        end;

     end;

end;

procedure TListRessources.DupliqueTo(Destination: TList);
var i :integer;
    x, y: POGResUsed;
begin

    Destination.Clear;

    if Count = 0 then exit;

    for i := 0 to Count - 1 do begin
       New(x);
       y := Items[i];

       x.IdOpt := y.IdOpt;
       x.prMetal := y.prMetal;
       x.prCristal  := y.prCristal;
       x.prDeuterium  := y.prDeuterium;
       x.prEnergie  := y.prEnergie;
       x.csEnergieUsed  := y.csEnergieUsed;
       x.csEnergieAllow  := y.csEnergieAllow;
       x.Activite        := y.Activite;

       x.ActiviteForOptimization := y.ActiviteForOptimization;

       x.Element := y.Element;
       x.ElementGID := y.ElementGID;
       x.ElementLVL := y.ElementLVL;

       Destination.Add(x);

    end;

end;


procedure TListRessources.ClearAndFree;
var i: integer;
    e: POGResUsed;
begin

    if Count = 0 then exit;

    for i := Count - 1 downto 0 do begin
        e := Items[i];
        Dispose(e);
    end;

    inherited Clear;
end;

procedure TListRessources.ResetOptimization;
var i: integer;
    e: POGResUsed;
begin

    if Count = 0 then exit;
    for i := Count - 1 downto 0 do begin
        e := Items[i];
        e.ActiviteForOptimization := -1;
    end;

end;

function TListRessources.GetProdParHeure: TOGRessourceAll;
begin
     Result := mcrGetCalculTotalParHeure(Self);
end;

procedure TListRessources.DoDebug(const Msg: string);
begin
     if Assigned(FDebugProc) then
        FDebugProc(Msg);
        
end;


function TListRessources.GetDonneesAPoster: string;
var i: integer;
    CurrRes: POGResUsed;
begin

    Result := '';


    if Count = 0 then begin
       exit;
    end;

    for i := 0 to Count - 1 do begin
        CurrRes := Items[i];

        if Result <> '' then begin
           Result := Result + '&';
        end;
        if CurrRes.IdOpt <> '' then begin
           Result := Result + CurrRes.IdOpt + '=' + IntToStr(CurrRes.Activite);
        end;

    end;

end;

procedure TListRessources.SendToDebugAllInfo;
var i: integer;
    CurrRes: POGResUsed;
    s: string;
begin

    if Count = 0 then begin
       DoDebug('Aucune ressource');

    end else begin

       for i := 0 to Count - 1 do begin
           CurrRes := Items[i];

           s := CurrRes.IdOpt;

           s := StringOfChar(' ', 8 - length(s)) + s + ' ';
           s := s + format('%5d %5d %5d - ', [CurrRes.prMetal, CurrRes.prCristal, CurrRes.prDeuterium]);

           if CurrRes.prEnergie > 0 then begin
              s := s + format('%6d', [CurrRes.prEnergie]);

           end else begin
              s := s + format('%4d/%d', [CurrRes.csEnergieUsed, CurrRes.csEnergieAllow]);
           end;

           DoDebug(s);

       end;

       DoDebug('');
    end;


end;


function TListRessources.Ajout(Element: TOGResUsed): POGResUsed;
var pElement: POGResUsed;
begin
    Result := nil;

    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Fait pointer l'élément

    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
    except
       Result := nil;
    end;

end;

function TListRessources.LoadLigneItem(Ligne: string): TOGResUsed;
var i: integer;
    s: string;
begin
    // r3=0,1253,0,0,626/626,626,last2

    // cE.prMetal, cE.prCristal, cE.prDeuterium, cE.prEnergie, cE.csEnergieUsed, cE.csEnergieAllow, cE.csEnergieAllow]);


    Result.IdOpt          := '';
    Result.prMetal        := 0;
    Result.prCristal      := 0;
    Result.prDeuterium    := 0;
    Result.prEnergie      := 0;
    Result.csEnergieUsed  := 0;
    Result.csEnergieAllow := 0;
    Result.Activite       := CNT_ACTIVITE_ERROR;
    Result.ActiviteForOptimization := -1;

    i := pos('=', Ligne);
    if i <= 0 then exit;
    System.Delete(Ligne, 1, i);

    i := sfcTokenCount(Ligne, ',');
    if i < 6 then exit;

    Result.prMetal        := sfcTokenGetInt(Ligne, 1, ',', 0);
    Result.prCristal      := sfcTokenGetInt(Ligne, 2, ',', 0);
    Result.prDeuterium    := sfcTokenGetInt(Ligne, 3, ',', 0);
    Result.prEnergie      := sfcTokenGetInt(Ligne, 4, ',', 0);

    s := sfcTokenGet(Ligne, 5, ',');
    Result.csEnergieUsed  := sfcTokenGetInt(s, 1, '/', 0);
    Result.csEnergieAllow := sfcTokenGetInt(s, 2, '/', 0);

    Result.Activite       := sfcTokenGetInt(Ligne, 6, ',', CNT_ACTIVITE_ERROR);
    Result.IdOpt          := sfcTokenGet(Ligne, 7, ',');

end;

function TListRessources.LoadFromFile(var F: TextFile; NbElements: integer): integer;
var Ligne: string;
    cE: TOGResUsed;
    i: integer;
begin

    Result := 0;
    i := 0;

    While NoT(EoF(F)) do begin
       ReadLn(F, Ligne);

       Ligne := trim(Ligne);
       if Ligne = '' then break;
       if Ligne[1] = '#' then Continue;
       if Ligne[1] = '/' then Continue;

       cE := LoadLigneItem(Ligne);

       if cE.Activite <> CNT_ACTIVITE_ERROR then begin
          Ajout(cE);
          Inc(Result);
       end else if i > 0 then
          break;

       Inc(i);

    end;


end;

procedure TListRessources.SaveToFile(var F: TextFile);
var i: integer;
    cE: POGResUsed;
    s: string;
begin

    if Count = 0 then begin
       WriteLn(F, '// Aucune ressource connue');
       WriteLn(F, '');
       exit;
    end;

    WriteLn(F, format('r=%d', [Count]));

    for i := 0 to Count - 1 do begin
       cE := Items[i];

       s := format('%d,%d,%d,%d,%d/%d,%d', [cE.prMetal, cE.prCristal, cE.prDeuterium, cE.prEnergie, cE.csEnergieUsed, cE.csEnergieAllow, cE.Activite]);

       if cE.IdOpt <> '' then
          s := s + ',' + cE.IdOpt;

       s := 'r' + IntToStr(i + 1) + '=' + s;

       WriteLn(F, s);
    end;

    WriteLn(F, '');

end;

end.
